//-------------------------------------------------------------------
//	Copyright (c) 2013  Zhirnov Andrey
//	This file is part of the "Noise Library" project.
//	See copyright notice in "linNoiseCL.h".
//-------------------------------------------------------------------

#pragma once

#include <Includes.h>
#include "../Source/CSource.h"
#include "../Program/CProgram.h"

#include "CImageViewerDummy.h"
#include "CImageViewerWin.h"

namespace Noise
{

	//
	// Context
	//

	class CContext
	{
	// types
	private:
		typedef array< CSourcePtr >		sources_t;
		typedef array< CProgramPtr >	programs_t;

		enum {
			_MAJOR_VER				= 0,
			_MINOR_VER				= 9,
			LIB_NOISE_CL_VERSION	= (_MAJOR_VER % 10) * 100 + (_MINOR_VER % 10) * 10,
		};
		
		typedef bool (* PCreateSource_t) (CSourcePtr &src, CContext *context, ESource type);
		typedef bool (* PCreateProgram_t) (CProgramPtr &prog, CContext *context, EProgram type);

		template <typename Proc, typename EType, typename ObjType>
		struct ConstructorType
		{
			Proc	proc;
			EType	type;
			///
			ConstructorType () : proc(null), type(NONE) {}
			ConstructorType (Proc proc, EType type) : proc(proc), type(type) {}

			bool Call (ObjType &src, CContext *context) const
			{
				ASSERT( proc != null );
				return proc( src, context, type );
			}
		};

		typedef ConstructorType< PCreateSource_t, ESource, CSourcePtr >	SourceType;
		typedef ConstructorType< PCreateProgram_t, EProgram, CProgramPtr >	ProgramType;

		typedef map< ESource, SourceType >		src_ctors_t;
		typedef map< EProgram, ProgramType >	prog_ctors_t;


	// variables
	private:
		src_ctors_t		_srcCtors;
		prog_ctors_t	_progCtors;
		sources_t		_sources;
		programs_t		_programs;
		CLDevice		_device;
		CLQueue			_queue;
		CImageViewer	_imageViewer;
		uvec3			_maxImageSize;
		EContextFlags	_flags;
		bool			_isInited;
		
		WINDOWS_ONLY(
		CFileSystem 	_fileSys;
		CLogger			_logger;
		TPerfTimer		_timer;
		)

	// methods
	private:
		void _Init ();

	public:
		CContext ();
		~CContext ();

		EResult Create (EContextFlags flags);
		EResult CreateCL (cl_platform_id platformId, cl_device_id deviceId, cl_context context);
		EResult CreateGL (void *dc, void *rc, EContextFlags flags);
		EResult CreateDX (void *dx, EContextFlags flags);
		void	Delete ();

		EResult SetInteger (EContextParameter pname, const int *v, int count);
		EResult GetInteger (EContextQuery pname, int *v, int count);

		CSourcePtr CreateSource (ESource type);
		CSourcePtr CreateSourceCopy (CSourcePtr src);
		CProgramPtr CreateProgram (EProgram type);
		
		void DeleteSource (CSourcePtr src);
		void DeleteProgram (CProgramPtr prog);

		bool RegisterSource (PCreateSource_t proc, ESource type);
		bool UnregisterSource (ESource type);

		bool RegisterProgram (PCreateProgram_t proc, EProgram type);
		bool UnregisterProgram (EProgram type);

		CLQueue *		GetQueue()				{ return &_queue; }
		CImageViewer *	GetImageViewer()		{ return &_imageViewer; }

		WINDOWS_ONLY(
		double			GetTime() const			{ return _timer.GetTime(); }
		)

		uvec3 const &	GetMaxImageSize() const	{ return _maxImageSize; }
	};


	inline CContext *	CONTEXT()	{ return Singleton::Instance< CContext >(); }


}	// Noise